"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : cm_install
Case Name   : cm_install指定-X参数路径正确，路径为相对路径
Create At   : 2022/11/15
Owner       : opentestcase012
Description :
    1: 配置xml文件中的cm相关参数;
    2: 数据库用户下执行cm_install,指定-X参数路径正确，路径为相对路径;
    3: gs_om查看集群状态;
    4: cm_ctl查看集群状态;
    5: 查看数据库用户下进程和定时任务;
    6: 执行cm_ctl命令;
Expect      :
    1: 成功
    2: 安装成功
    3: 数据库状态正常
    4: 集群状态正常
    5: om_monitor、cm_agent、cm_server进程存在，有om_monitor的定时任务
    6: 执行成功
History     :
    modified by opentestcase012 at 2023-5-22:添加普通用户对cm包的执行权限
"""
import os
import unittest

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro

Primary_SH = CommonSH('PrimaryDbUser')


@unittest.skipIf(3 != Primary_SH.get_node_num(), '需1主2备环境，否则不执行')
class Tools(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pri_user = Node('PrimaryDbUser')
        self.pri_root = Node('PrimaryRoot')
        self.primary_sh = CommonSH('PrimaryDbUser')
        self.sta1_user = Node('Standby1DbUser')
        self.sta1_root = Node('Standby1Root')
        self.sta2_user = Node('Standby2DbUser')
        self.sta2_root = Node('Standby2Root')
        self.common = Common()
        self.constant = Constant()
        self.cm_tool_old = os.path.join(macro.DB_INSTANCE_PATH, '..',
                                        'app', 'tool', 'cm_tool', '*')
        path = macro.DB_INSTANCE_PATH
        for i in range(len(path.split('/')) - 1):
            path = os.path.dirname(path)
        user_home = os.path.join(path, 'home', self.pri_user.ssh_user)
        self.cm_tool_new = os.path.join(user_home, 'cm_tool')
        self.cm_dir = os.path.join(macro.DB_INSTANCE_PATH, '..', 'cm')
        self.cm_xml = os.path.join(user_home, 'cm.xml')
        self.xml_relative_path = os.path.join('..', 'cm.xml')

        text = '-----前置:查看term和lsn; expect:成功---'
        self.log.info(text)
        sql_cmd = f'select term, lsn from pg_last_xlog_replay_location();'
        sql_result = Primary_SH.execut_db_sql(sql=sql_cmd)
        self.log.info(sql_result)
        if '0/0' in sql_result:
            cmd = f'source {macro.DB_ENV_PATH};' \
                f'gs_ctl switchover -D {macro.DB_INSTANCE_PATH}'
            self.log.info(cmd)
            res = self.common.get_sh_result(self.sta1_user, cmd)
            self.assertIn(self.constant.SWITCHOVER_SUCCESS_MSG, res,
                          "执行失败:" + text)
            res = self.common.get_sh_result(self.pri_user, cmd)
            self.assertIn(self.constant.SWITCHOVER_SUCCESS_MSG, res,
                          "执行失败:" + text)
            sql_result = Primary_SH.execut_db_sql(sql=sql_cmd)
            self.log.info(sql_result)
        self.assertNotIn('0/0', sql_result, "执行失败:" + text)

    def test_standby(self):
        text = '-----查看主机名-----'
        self.log.info(text)
        host_pri = self.common.get_sh_result(self.pri_root, "uname -n")
        host_sta1 = self.common.get_sh_result(self.sta1_root, "uname -n")
        host_sta2 = self.common.get_sh_result(self.sta2_root, "uname -n")
        self.assertIsNotNone(host_pri and host_sta1 and host_sta2,
                             '执行失败:' + text)
        hosts = f"{host_pri},{host_sta1},{host_sta2}"
        node_ip = f"{self.pri_user.db_host},{self.sta1_user.db_host}," \
            f"{self.sta2_user.db_host}"
        match_pri = f'value="{host_pri}"'
        match_sta1 = f'value="{host_sta1}"'
        match_sta2 = f'value="{host_sta2}"'

        self.log.info('-----查询系统和数据库版本-----')
        os_cpu = self.pri_root.sh('cat /etc/*release;'
                                  'uname -a').result()
        self.log.info(os_cpu)
        find_cmd = f'source {macro.DB_ENV_PATH};' \
            f'gaussdb -V'
        find_ver_msg = self.common.get_sh_result(self.pri_user, find_cmd)
        assert find_ver_msg.find('compiled at') > -1
        db_release_version = find_ver_msg.split()[2]

        self.log.info('-----获取cm压缩包路径,赋予普通用户执行权限-----')
        cm_tgz = ''
        if 'CentOS Linux 7' in os_cpu:
            cm_tgz = f'openGauss-{db_release_version}-CentOS-64bit-cm.tar.gz'
        elif 'openEuler 20.03' in os_cpu:
            cm_tgz = f'openGauss-{db_release_version}-openEuler-64bit-cm.tar.gz'
        cmpkg_old = os.path.join(os.path.dirname(macro.DB_SCRIPT_PATH), cm_tgz)
        cmpkg = os.path.join(macro.DB_INSTANCE_PATH, cm_tgz)
        cmd = f'cp {cmpkg_old} {cmpkg};' \
            f'chown -R {self.pri_user.ssh_user}:{self.pri_user.ssh_user} ' \
            f'{cmpkg};'
        res = self.common.get_sh_result(self.pri_root, cmd)
        self.assertEqual('', res, '执行失败:' + text)

        text = '-----查询系统未使用端口-----'
        self.log.info(text)
        global port
        for count in range(10):
            port = self.common.get_not_used_port(self.pri_root)
            self.log.info(port)
            standby_port_check_cmd = f'netstat -tlnp | grep {port}'
            sta1_check_msg = self.common.get_sh_result(self.sta1_root,
                                                       standby_port_check_cmd)
            sta2_check_msg = self.common.get_sh_result(self.sta2_root,
                                                       standby_port_check_cmd)
            if not (sta1_check_msg and sta2_check_msg):
                self.assertNotEqual(0, port, '执行失败:' + text)
                break
            else:
                continue

        text = '-----step1:配置xml文件中的cm相关参数; expect:成功-----'
        self.log.info(text)
        cminfo_pri = f'\\r\\n            ' \
            f'<PARAM name="cmDir" value="{self.cm_dir}"/>\\r\\n            ' \
            f'<PARAM name="cmsNum" value="1"/>\\r\\n            ' \
            f'<PARAM name="cmServerPortBase" value="{port}"/>\\r\\n' \
            f'            <PARAM name="cmServerPortStandby" value="{port}"/>' \
            f'\\r\\n            ' \
            f'<PARAM name="cmServerlevel" value="1"/>\\r\\n            ' \
            f'<PARAM name="cmServerListenIp1" value="{node_ip}"/>' \
            f'\\r\\n            ' \
            f'<PARAM name="cmServerRelation" value="{hosts}"/>\\r\\n'
        cminfo_sta = f'            <PARAM name="cmDir" value="{self.cm_dir}"/>'
        sed_cmd = f"cp {macro.DB_XML_PATH} {self.cm_xml};" \
            f"sed -i '/{match_pri}/a\\{cminfo_pri}' {self.cm_xml};" \
            f"sed -i '/{match_sta1}/a\\{cminfo_sta}' {self.cm_xml};" \
            f"sed -i '/{match_sta2}/a\\{cminfo_sta}' {self.cm_xml};" \
            f"cat {self.cm_xml};"
        self.log.info(sed_cmd)
        sed_msg = self.common.get_sh_result(self.pri_user, sed_cmd)
        self.assertEqual(3, sed_msg.count(self.cm_dir), '执行失败:' + text)

        text = '-----step2:数据库用户下执行cm_install,指定-X参数路径正确，路径为相对路径 ' \
               'expect:安装成功-----'
        self.log.info(text)
        cp_cmd = f'mkdir {self.cm_tool_new};' \
            f'cp -r {self.cm_tool_old} {self.cm_tool_new};' \
            f'cd {self.cm_tool_new};'
        self.log.info(cp_cmd)
        cp_msg = self.common.get_sh_result(self.pri_user, cp_cmd)
        self.assertEqual('', cp_msg, '执行失败:' + text)
        install_cmd = f'./cm_install -X {self.xml_relative_path} ' \
            f'-e {macro.DB_ENV_PATH} --cmpkg {cmpkg}'
        self.log.info(install_cmd)
        install_res = self.common.do_cminstall(self.pri_user, self.cm_tool_new,
                                               install_cmd)
        self.assertIn('Install CM tool success', install_res, '执行失败:' + text)

        text = '-----step3:gs_om查看集群状态;expect: 集群状态正常-----'
        self.log.info(text)
        status_msg = Primary_SH.get_db_cluster_status('detail')
        self.log.info(status_msg)
        self.assertIn(self.constant.CLUSTER_NORMAL_MSG, status_msg,
                      "执行失败:" + text)
        self.assertIn('CMServer State', status_msg, "执行失败:" + text)

        text = '-----step4:cm_ctl查看集群状态 expect:集群状态正常-----'
        self.log.info(text)
        show_status = f'source {macro.DB_ENV_PATH};' \
            f'cm_ctl query -Civdp'
        status_msg = self.common.get_sh_result(self.pri_user, show_status)
        self.assertIn(self.constant.CLUSTER_NORMAL_MSG, status_msg,
                      "执行失败:" + text)
        self.assertIn('CMServer State', status_msg, "执行失败:" + text)

        text = '----step5:查看数据库用户下进程和定时任务 ' \
               'expect:om_monitor、cm_agent、cm_server进程存在，有om_monitor的定时任务----'
        self.log.info(text)
        show_cmd = "crontab -l;ps ux|egrep 'cm_server|cm_agent|om_monitor';"
        process_res = self.primary_sh.exec_gs_ssh(show_cmd)
        self.assertEqual(3, process_res.count('bin/cm_server'), "执行失败:" + text)
        self.assertEqual(3, process_res.count('bin/cm_agent'), "执行失败:" + text)
        self.assertGreaterEqual(6, process_res.count('om_monitor -L'),
                                "执行失败:" + text)
        self.assertEqual(6, process_res.count('*/1 * * * *'), "执行失败:" + text)

        text = '-----step6:执行cm_ctl命令 expect:成功-----'
        self.log.info(text)
        cm_cmd = f'source {macro.DB_ENV_PATH};' \
            f'cm_ctl stop -n 2 -D {macro.DB_INSTANCE_PATH};' \
            f'cm_ctl build -n 2 -D {macro.DB_INSTANCE_PATH};' \
            f'cm_ctl start;' \
            f'cm_ctl switchover -n 2 -D {macro.DB_INSTANCE_PATH};' \
            f'cm_ctl switchover -a'
        cm_msg = self.common.get_sh_result(self.pri_user, cm_cmd)
        self.assertIn(self.constant.cm_stop_instance_success_msg, cm_msg,
                      "执行失败:" + text)
        self.assertIn(self.constant.cm_build_success_msg, cm_msg,
                      "执行失败:" + text)
        self.assertIn(self.constant.cm_start_success_msg, cm_msg,
                      "执行失败:" + text)
        self.assertEqual(cm_msg.count(self.constant.cm_switchover_success_msg),
                         2, "执行失败:" + text)

    def tearDown(self):
        self.log.info('----清理环境----')
        text1 = '-----卸载CM expect:成功-----'
        self.log.info(text1)
        uninstall_cmd = f'cd {self.cm_tool_new};' \
            f'chmod +x cm_uninstall;' \
            f'./cm_uninstall -X {macro.DB_XML_PATH} -e {macro.DB_ENV_PATH} ' \
            f'--deleteData'
        self.log.info(uninstall_cmd)
        uninstall_res = self.common.get_sh_result(self.pri_user, uninstall_cmd)

        text2 = '----删除xml文件; expect:删除成功----'
        self.log.info(text2)
        rm_cmd = f'rm -rf {self.cm_xml};'
        self.log.info(rm_cmd)
        self.common.get_sh_result(self.pri_root, rm_cmd)
        check_cmd = f'if [[ -e {self.cm_xml} ]]; ' \
            f'then echo "exists"; else echo "not exists"; fi'
        rm_msg_pri = self.common.get_sh_result(self.pri_root, check_cmd)

        text3 = '-----删除tool目录 expect:成功-----'
        self.log.info(text3)
        del_cmd = f'rm -rf {self.cm_tool_new}'
        self.common.get_sh_result(self.pri_root, del_cmd)
        check_cmd = f'if [ -d {self.cm_tool_new} ]; ' \
            f'then echo "exists"; else echo "not exists"; fi'
        del_msg = self.common.get_sh_result(self.pri_root, check_cmd)

        self.assertIn('Uninstall CM tool success', uninstall_res,
                      '执行失败:' + text1)
        self.assertEqual('not exists', rm_msg_pri, '执行失败:' + text2)
        self.assertEqual('not exists', del_msg, '执行失败:' + text3)
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
